﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;

namespace client
{
    class GestorSeguranca
    {
        public string _uniqueID = "";
        private Utilizador _util;
        private byte[] _chaveServidor;
        public ServiceReference1.Service1Client _sv;
        private Label labelResultado;
        private TextBox caixaTexto;
        private string chavePublicaCliente = "./certificados/estg.dei.si.b_gmail.com.cer";
        private string chavePrivadaClient = "./certificados/estg.dei.si.b_gmail.com.pfx";
        private string chavePrivadaPassword = "ei.si";


        public void start()
        {

            _sv = new ServiceReference1.Service1Client();
            //1 passo
            gerarSerial();
            //2 passo
            buscarCerServidor();
            //3 passo
            guardaNoCliente();
            //5 passo
            byte[] dadosEncriptados = encriptarDados(_uniqueID);
            ////6 passo
            byte[] dadosAssinados = assinarDados(dadosEncriptados);
            ////7 passo
            enviarParaServidor(dadosAssinados);

        }
        #region enviar Dados
        private void saveID(Utilizador util)
        {
            GestorSerialize gser = new GestorSerialize();
            gser.Save(util);

        }

        private byte[] GetMyCer()
        {
            string fullFilePath = @"c:\certificados\estg.dei.si.a_gmail.com.cer";
            FileStream fs = File.OpenRead(fullFilePath);
            try
            {
                byte[] bytes = new byte[fs.Length];
                fs.Read(bytes, 0, Convert.ToInt32(fs.Length));
                fs.Close();
                return bytes;
            }
            finally
            {
                fs.Close();
            }
        }

        public byte[] encriptarDados(string dados)
        {
            Debug.WriteLine("Dados Cliente: " + dados);

            byte[] dadosBytes = Encoding.UTF8.GetBytes(dados);
            // obter dados cifrar           
            ContentInfo info = new ContentInfo(dadosBytes);
            // obter certificado 
            X509Certificate2 cer = new X509Certificate2("./certificados/chavePublicaServidor.cer");
            CmsRecipient reci = new CmsRecipient(cer);

            // cifrar
            EnvelopedCms env = new EnvelopedCms(info);
            env.Encrypt(reci);
            byte[] res = env.Encode();
            Debug.WriteLine("client encrypt:" + res.Length.ToString());

            // obter dados cifrados (PKCS#7)
            return res;
        }

        public byte[] assinarDados(byte[] dadosEncriptados)
        {

            ContentInfo info = new ContentInfo(dadosEncriptados);

            // obter certificado
            X509Certificate2 cer = new X509Certificate2("c:/certificados/estg.dei.si.b_gmail.com.pfx", "ei.si");

            CmsSigner sign = new CmsSigner(cer);

            // calcular a Assinatura
            SignedCms signCms = new SignedCms(info, false);
            signCms.ComputeSignature(sign);

            // obter Mensagem (PKCS#7)
            byte[] res = signCms.Encode();

            Debug.WriteLine("client assinar:" + res.Length.ToString());

            return res;
        }

        public bool guardaNoCliente()
        {
            try
            {
                // Open file for reading
                System.IO.FileStream fs = new System.IO.FileStream("./certificados/chavePublicaServidor.cer", System.IO.FileMode.Create, System.IO.FileAccess.Write);

                fs.Write(_chaveServidor, 0, _chaveServidor.Length);

                // close file stream
                fs.Close();

                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("SavePublickey cert: "+ ex.Message);
                return false;
            }
            
        }

        public bool buscarCerServidor()
        {

           _chaveServidor = _sv.chavePublica();

           return true;
        }


        public bool gerarSerial()
        {
            UniqueId id = new UniqueId();

            if (!File.Exists("./certificados/utilizador.txt"))
           {
               
               _uniqueID = id.GetUniqueID(); 

               _util = id.partirString(_uniqueID);
               saveID(_util);               
           }
           else
           {
               _util = LoadID();
               _uniqueID = id.GetUniqueID(_util.SerialUnico);
           }
            

            return true;
        }


        private Utilizador LoadID()
        {
            GestorSerialize gser = new GestorSerialize();
            _util = new Utilizador();
            return gser.Load(_util);
        }


        public bool enviarParaServidor(byte[] dadosAssinados)
        {
            byte[] res = Sv.validaDados(GetMyCer(), dadosAssinados);
            tratarResposta(res);
            return true;
        }

        #endregion

        #region tratar resposta

        private void tratarResposta(byte[] resposta)
        {
            string dadosLimpos = verificarDescriptar(resposta);
            //caixaTexto.Text += Environment.NewLine + dadosLimpos;

            List<string> lista = dadosLimpos.Split('#').ToList<string>();

            if (lista[1].Equals("s"))
                labelResultado.Text = "OK";
            else
                labelResultado.Text = "NOT OK";
        }

        private string verificarDescriptar(byte[] dadosAssinados)
        {
            //Descodificar a mensagem
            SignedCms signedCms = new SignedCms();
            signedCms.Decode(dadosAssinados);

            //verificar a assinatura
            try
            {
                signedCms.CheckSignature(false);
                caixaTexto.Text += Environment.NewLine + "assinatura valida";
            }
            catch (Exception ex)
            {
                labelResultado.Text = "assinatura invalida ou certificado invalido";
            }

            //obter o certificado (!!!)
            X509Certificate2 cert = new X509Certificate2(chavePrivadaClient, chavePrivadaPassword);


            //decifrar
            EnvelopedCms envelope = new EnvelopedCms();
            envelope.Decode(signedCms.ContentInfo.Content);
            //envelope.Decrypt(); //vai a procura automaticamente

            envelope.Decrypt(new X509Certificate2Collection(cert));

            string dadosLimpos = Encoding.UTF8.GetString(envelope.ContentInfo.Content);

            return dadosLimpos;
        }

        #endregion



        #region gets e sets
        public TextBox CaixaTexto
        {
            get { return caixaTexto; }
            set { caixaTexto = value; }
        }
        public ServiceReference1.Service1Client Sv
        {
            get { return _sv; }
            set { _sv = value; }
        }
        public Label LabelResultado
        {
            get { return labelResultado; }
            set { labelResultado = value; }
        }

        #endregion
    }
}
